<template>
  <div
    :class="[{
               'el-form-item': rules != null && (typeof rules === 'object'),
               'is-error': validateState === 'error',
               'is-validating': validateState === 'validating',
               'is-success': validateState === 'success',
               'is-required': isRequired || required
             },
             sizeClass ? 'el-form-item--' + sizeClass : ''
    ]"
  >
    <el-popover
      :disabled="disabled"
      placement="top"
      trigger="hover"
      :popper-class="popperClass"
      :content="validateMessage"
    >
      <slot slot="reference" />
    </el-popover>
  </div>
</template>
<script>
import AsyncValidator from 'async-validator'
import emitter from 'element-ui/src/mixins/emitter'
import objectAssign from 'element-ui/src/utils/merge'
import { noop } from 'element-ui/src/utils/util'
export default {
  name: 'TableRules',

  componentName: 'ElFormItem',

  mixins: [emitter],

  provide() {
    return {
      elFormItem: this
    }
  },

  props: {
    required: {
      type: Boolean,
      default: undefined
    },
    rules: {
      type: [Object],
      default: null
    },
    error: {
      type: String,
      default: null
    },
    validateStatus: {
      type: String,
      default: null
    },
    showMessage: {
      type: Boolean,
      default: true
    },
    value: {
      type: [String, Number, Boolean, Array, Object, Function, Promise],
      default: null
    },
    size: {
      type: String,
      default: null
    }
  },
  data() {
    return {
      validateState: '',
      validateMessage: '',
      validateDisabled: false,
      validator: {},
      isNested: false,
      computedLabelWidth: '',
      popperClass: 'tooltip'
    }
  },
  computed: {
    isRequired() {
      const rules = this.getRules()
      let isRequired = false

      if (rules && rules.length) {
        rules.every(rule => {
          if (rule.required) {
            isRequired = true
            return false
          }
          return true
        })
      }
      return isRequired
    },
    elFormItemSize() {
      return this.size
    },
    sizeClass() {
      return this.elFormItemSize || (this.$ELEMENT || {}).size
    },
    disabled() {
      return !(this.validateState === 'error' && this.showMessage)
    }
  },
  watch: {
    error: {
      immediate: true,
      handler(value) {
        this.validateMessage = value
        this.validateState = value ? 'error' : ''
      }
    },
    validateStatus(value) {
      this.validateState = value
    }
  },
  mounted() {
    this.addValidateEvents()
  },
  methods: {
    validate(trigger, callback = noop) {
      this.validateDisabled = false
      const that = this
      var isError = false
      Object.keys(this.rules).forEach((name, index, array) => {
        if (isError) return
        const rules = that.getFilteredRule(trigger, name)
        if ((!rules || rules.length === 0) && that.required === undefined) {
          callback()
          return true
        }

        that.validateState = 'validating'

        const descriptor = {}
        if (rules && rules.length > 0) {
          rules.forEach(rule => {
            delete rule.trigger
          })
        }
        descriptor[name] = rules

        const validator = new AsyncValidator(descriptor)
        const model = {}

        model[name] = that.value[name]

        validator.validate(model, { firstFields: true }, (errors, invalidFields) => {
          that.validateState = !errors ? 'success' : 'error'
          that.validateMessage = errors ? errors[0].message : ''

          callback(that.validateMessage, invalidFields)
        })
        if (that.validateState === 'error') isError = true
      })
    },
    clearValidate() {
      this.validateState = ''
      this.validateMessage = ''
      this.validateDisabled = false
    },
    getRules(name) {
      const selfRules = this.rules[name]
      const requiredRule = this.required !== undefined ? { required: !!this.required } : []

      return [].concat(selfRules || []).concat(requiredRule)
    },
    getFilteredRule(trigger, name) {
      const rules = this.getRules(name)

      return rules.filter(rule => {
        if (!rule.trigger || trigger === '') return true
        if (Array.isArray(rule.trigger)) {
          return rule.trigger.indexOf(trigger) > -1
        } else {
          return rule.trigger === trigger
        }
      }).map(rule => objectAssign({}, rule))
    },
    onFieldBlur() {
      this.validate('blur')
    },
    onFieldChange() {
      if (this.validateDisabled) {
        this.validateDisabled = false
        return
      }

      this.validate('change')
    },
    addValidateEvents() {
      const rules = this.getRules()

      if (rules.length || this.required !== undefined) {
        this.$on('el.form.blur', this.onFieldBlur)
        this.$on('el.form.change', this.onFieldChange)
      }
    },
    removeValidateEvents() {
      this.$off()
    }
  }
}
</script>

<style scoped>
.el-form-item{
  margin-bottom: 0;
}
</style>
<style>
.tooltip{
  color: #F56C6C;
  padding-bottom: 10px;
  padding-top: 10px;
  /*box-shadow: 1px 3px 12px 0 rgba(0,0,0,.4);*/
}
</style>
